using System;
using System.Diagnostics;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Reflection;
using System.ComponentModel;
using System.Xml;
using System.Xml.Serialization;
using System.Xml.XPath;

using SandcastleBuilder.Utils;
using SandcastleBuilder.Utils.PlugIn;

using Darilek.SandcastleExtensions.Utilities;
using Darilek.SandcastleExtensions.PlugIns.Configuration;

namespace Darilek.SandcastleExtensions.PlugIns
{
	public class ResolveReferencePlugIn : IPlugIn
	{
		private const string COMPONENT_NAME = "Microsoft.Ddue.Tools.ResolveReferenceLinksComponent2";
		private readonly string COMPONENT_XPATH = String.Format("//components/component[@type='{0}']", COMPONENT_NAME);

		private ExecutionPointCollection _executionPoints;
		private BuildProcess _buildProcess;
		private ResolveReferencePlugInConfiguration _settings;

		#region IPlugIn Members

		public string ConfigurePlugIn(string currentConfig)
		{
			using (ResolveReferenceConfigDlg dlg = new ResolveReferenceConfigDlg(currentConfig))
			{
				if (dlg.ShowDialog() == DialogResult.OK)
				{
					return dlg.Configuration;
				}
			}

			return currentConfig;

		}

		public string Copyright
		{
			get
			{
				Assembly asm = Assembly.GetExecutingAssembly();
				AssemblyCopyrightAttribute copyright =
					(AssemblyCopyrightAttribute)Attribute.GetCustomAttribute(
						asm, typeof(AssemblyCopyrightAttribute));

				return copyright.Copyright;
			}
		}

		public string Description
		{
			get { return "This plugin provides management of additional targets for resolving index links to custom components"; }
		}

		public void Execute(ExecutionContext context)
		{
			if (context.BuildStep != BuildStep.MergeCustomConfigs && context.Behavior != ExecutionBehaviors.After)
			{
				context.Executed = false;
				return;
			}

			string sandcastleConfigPath = _buildProcess.WorkingFolder + "sandcastle.config";
			XmlDocument sandcastleConfig = new XmlDocument();
			sandcastleConfig.Load(sandcastleConfigPath);

			XmlNodeList componentNodeList = sandcastleConfig.SelectNodes(COMPONENT_XPATH);
			if (componentNodeList.Count != 1)
			{
				throw new BuilderException("Required component configuration node not found or defined twice or more");
			}

			XmlNode componentNode = componentNodeList[0];

			foreach (TargetItem targetItem in _settings.Targets)
			{
				if (targetItem.Active == false)
					continue;

				XmlElement targetElement = sandcastleConfig.CreateElement("targets");
				targetElement.Attributes.Append(sandcastleConfig.CreateAttribute("base")).Value = targetItem.BaseDir;
				targetElement.Attributes.Append(sandcastleConfig.CreateAttribute("files")).Value = targetItem.Files;
				targetElement.Attributes.Append(sandcastleConfig.CreateAttribute("recurse")).Value = targetItem.Recurse.ToString();
				targetElement.Attributes.Append(sandcastleConfig.CreateAttribute("type")).Value = targetItem.LinkType;

				componentNode.AppendChild(targetElement);
			}

			sandcastleConfig.Save(sandcastleConfigPath);

			context.Executed = true;
		}

		public ExecutionPointCollection ExecutionPoints
		{
			get
			{
				if (_executionPoints == null)
				{
					_executionPoints = new ExecutionPointCollection();
					_executionPoints.Add(new ExecutionPoint(BuildStep.MergeCustomConfigs, ExecutionBehaviors.After));
				}

				return _executionPoints;

			}
		}

		public void Initialize(SandcastleBuilder.Utils.BuildProcess buildProcess, System.Xml.XPath.XPathNavigator configuration)
		{
			_buildProcess = buildProcess;
			_settings = ConfigurationSerializer.LoadConfiguration<ResolveReferencePlugInConfiguration>(configuration.InnerXml);
		}

		public string Name
		{
			get { return "Resolve Reference Link PlugIn"; }
		}

		public bool RunsInPartialBuild
		{
			get { return false; }
		}

		public Version Version
		{
			get
			{
				Assembly asm = Assembly.GetExecutingAssembly();
				FileVersionInfo fvi = FileVersionInfo.GetVersionInfo(
					asm.Location);

				return new Version(fvi.ProductVersion);
			}
		}

		#endregion

		#region IDisposable Members

		//=====================================================================
		// IDisposable implementation

		/// <summary>
		/// This handles garbage collection to ensure proper disposal of the
		/// plug-in if not done explicity with <see cref="Dispose()"/>.
		/// </summary>
		~ResolveReferencePlugIn()
		{
			this.Dispose(false);
		}

		/// <summary>
		/// This implements the Dispose() interface to properly dispose of
		/// the plug-in object.
		/// </summary>
		/// <overloads>There are two overloads for this method.</overloads>
		public void Dispose()
		{
			this.Dispose(true);
			GC.SuppressFinalize(this);
		}

		/// <summary>
		/// This can be overridden by derived classes to add their own
		/// disposal code if necessary.
		/// </summary>
		/// <param name="disposing">Pass true to dispose of the managed
		/// and unmanaged resources or false to just dispose of the
		/// unmanaged resources.</param>
		protected virtual void Dispose(bool disposing)
		{
			// TODO: Implement this if necessary
		}
		#endregion
	}
}
